#include "app_update.h"
#include <string.h>
#include "gd32f4xx.h"
#include "gd32f4xx_fmc.h"
#include "gd32f4xx_usart.h"
#include "gd32f4xx_gpio.h"
#include "gd32f4xx_rcu.h"
#include "led.h"
#include "device_info.h"
// CRC16查表
static const uint16_t crc16_table[256] = {
    0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
    0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
    0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
    0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
    0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
    0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
    0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
    0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
    0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
    0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
    0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
    0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
    0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
    0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
    0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
    0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
    0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
    0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
    0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
    0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
    0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
    0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
    0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
    0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
    0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
    0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
    0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
    0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
    0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
    0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
    0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
    0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};

// 串口缓冲区定义(全局变量)
uart_buffer_t uart_buf = {0};

// 供中断使用的缓冲区写入函数
uint8_t uart_buf_write(uint8_t data)
{
    uint8_t next = (uart_buf.wr_index + 1) % FRAME_MAX_SIZE;
    if(next != uart_buf.rd_index) {
        uart_buf.buf[uart_buf.wr_index] = data;
        uart_buf.wr_index = next;
        return 1;  // 写入成功
    }
    return 0;  // 缓冲区满
}

// CRC16计算 - 与上位机使用相同的MODBUS CRC16
uint16_t calculate_crc16(uint8_t *data, uint16_t length)
{
    uint16_t crc = 0xFFFF;
    for(uint16_t i = 0; i < length; i++) {
        crc ^= data[i];
        for(uint8_t j = 0; j < 8; j++) {
            if(crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc = crc >> 1;
            }
        }
    }
    return crc;
}

// 发送数据帧
void send_frame(uint8_t cmd, uint8_t *data, uint16_t length)
{
    frame_t frame;
    frame.sof = FRAME_SOF;
    frame.cmd = cmd;
    frame.length = length;
    if(data && length > 0) {
        memcpy(frame.data, data, length);
    }
    
    // 构建帧头部分用于计算CRC
    uint8_t header[4];
    header[0] = frame.sof;
    header[1] = frame.cmd;
    header[2] = frame.length & 0xFF;
    header[3] = (frame.length >> 8) & 0xFF;
    
    // 计算CRC (方式与上位机一致: SOF + CMD + LEN + DATA)
    uint16_t crc = calculate_crc16(header, 4);
    if(length > 0) {
        crc = calculate_crc16(frame.data, length);
    }
    frame.crc16 = crc;
    
    // 发送数据
    usart_data_transmit(USART0, frame.sof);
    usart_data_transmit(USART0, frame.cmd);
    usart_data_transmit(USART0, frame.length & 0xFF);
    usart_data_transmit(USART0, (frame.length >> 8) & 0xFF);
    for(uint16_t i = 0; i < frame.length; i++) {
        usart_data_transmit(USART0, frame.data[i]);
    }
    usart_data_transmit(USART0, frame.crc16 & 0xFF);
    usart_data_transmit(USART0, (frame.crc16 >> 8) & 0xFF);
}

// 数据包处理
static void process_frame(frame_t *frame)
{
    switch(frame->cmd) {
        case CMD_UPDATE_REQ:
            // 收到升级请求，发送确认
            send_frame(CMD_UPDATE_ACK, NULL, 0);
            // 设置跳转标志并复位
            enter_bootloader();
            break;
            
        case CMD_UPDATE_DATA:
            // 在APP中收到数据指令，转发给bootloader
            send_frame(CMD_UPDATE_ACK, NULL, 0);
            
            // 延迟一小段时间后跳转到bootloader
            for(volatile uint32_t i = 0; i < 100000; i++);
            enter_bootloader();
            break;
            
        case CMD_UPDATE_END:
            // 收到升级结束指令
            send_frame(CMD_UPDATE_ACK, NULL, 0);
            break;
            
        case CMD_UPDATE_VERIFY:
            // 收到验证指令
            send_frame(CMD_UPDATE_ACK, NULL, 0);
            break;
            
        case CMD_UPDATE_RESET:
            // 收到复位指令
            send_frame(CMD_UPDATE_ACK, NULL, 0);
            
            // 延迟一小段时间后进行复位
            for(volatile uint32_t i = 0; i < 100000; i++);
            NVIC_SystemReset();
            break;
            
        default:
            // 不支持的指令
            send_frame(CMD_UPDATE_NACK, NULL, 0);
            break;
    }
}

// 数据处理
void app_update_process(void)
{
    static enum {
        WAIT_SOF,
        WAIT_CMD,
        WAIT_LEN_L,
        WAIT_LEN_H,
        WAIT_DATA,
        WAIT_CRC_L,
        WAIT_CRC_H
    } state = WAIT_SOF;

    static frame_t frame;
    static uint16_t data_count = 0;
    static uint16_t frame_length = 0;
    
    while(uart_buf.rd_index != uart_buf.wr_index) {
        uint8_t data = uart_buf.buf[uart_buf.rd_index];
        uart_buf.rd_index = (uart_buf.rd_index + 1) % FRAME_MAX_SIZE;
        
        switch(state) {
            case WAIT_SOF:
                if(data == FRAME_SOF) {
                    state = WAIT_CMD;
                }
                break;
                       led_toggle(LED1);
    case WAIT_CMD:
                frame.cmd = data;
                state = WAIT_LEN_L;
                break;
                
            case WAIT_LEN_L:
                frame_length = data;
                state = WAIT_LEN_H;
                break;
                
            case WAIT_LEN_H:
                frame_length |= (data << 8);
                if(frame_length > FRAME_MAX_SIZE) {
                    state = WAIT_SOF;
                    break;
                }
                frame.length = frame_length;
                data_count = 0;
                state = frame_length ? WAIT_DATA : WAIT_CRC_L;
                break;
                
            case WAIT_DATA:
                frame.data[data_count++] = data;
                if(data_count >= frame_length) {
                    state = WAIT_CRC_L;
                }
                break;
                
            case WAIT_CRC_L:
                frame.crc16 = data;
                state = WAIT_CRC_H;
                break;
                
            case WAIT_CRC_H:
                frame.crc16 |= (data << 8);
                // 验证CRC
                uint8_t header[4];
                header[0] = FRAME_SOF;  // 帧中的SOF
                header[1] = frame.cmd;
                header[2] = frame.length & 0xFF;
                header[3] = (frame.length >> 8) & 0xFF;
                
                // 计算CRC (方式与上位机一致: SOF + CMD + LEN + DATA)
                uint16_t calculated_crc = calculate_crc16(header, 4);
                if(frame.length > 0) {
                    calculated_crc = calculate_crc16(frame.data, frame.length);
                }
                
                if(frame.crc16 == calculated_crc) {
                    process_frame(&frame);
                }
                state = WAIT_SOF;
                break;
        }
    }
}

fmc_state_enum write_flash_data(uint32_t addr, uint8_t *data, uint32_t size)
{
    fmc_state_enum status = FMC_READY;
    uint32_t i;

    /* 1. 解锁Flash */
    fmc_unlock();

    /* 2. 清除标志位 */
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR |
                   FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);

    /* 3. 按32位写入 */
    for (i = 0; i < size; i += 4)
    {
        uint32_t temp_word;

        /* 组合32位数据 */
        temp_word = ((uint32_t)data[i + 3] << 24) |
                    ((uint32_t)data[i + 2] << 16) |
                    ((uint32_t)data[i + 1] << 8) |
                    data[i];

        status = fmc_word_program(addr + i, temp_word);

        if (status != FMC_READY)
        {
            break;
        }

        /* 等待写入完成 */
        while (FMC_BUSY == fmc_flag_get(FMC_FLAG_END))
            ;

        /* 验证写入是否正确 */
        if (*(uint32_t *)(addr + i) != temp_word)
        {
            status = FMC_PGMERR;
            break;
        }
    }

    /* 4. 锁定Flash */
    fmc_lock();

    return status;
}

void clear_app_valid_flag(void)
{
    uint32_t zero_data = 0;

    /* 擦除包含设备信息的页 */
    fmc_unlock();
    if (fmc_page_erase(DEVICE_INFO_ADDR) == FMC_READY)
    {
        /* 写入0 */
        write_flash_data(DEVICE_INFO_ADDR, (uint8_t *)&zero_data, 4);
    }
    fmc_lock();

    /* 复位系统 */
    NVIC_SystemReset();
}

void jump_to_bootloader(void)
{
    clear_app_valid_flag();
    /* 1. 设置跳转标志 */
    *(__IO uint32_t *)0x20000000 = 0x55AA55AA; // 在SRAM起始位置设置标志

    /* 2. 关闭所有中断 */
    __disable_irq();

    /* 3. 执行系统复位 */
    NVIC_SystemReset();
}

// 跳转到Bootloader
void enter_bootloader(void)
{
    #define DEVICE_INFO_SIZE 0x40                                    // 64字节
    #define DEVICE_INFO_ADDR (0x080C0000 + 0x40000 - DEVICE_INFO_SIZE) // 0x080FFFC0

    // 1. 清除APP有效标志
    uint32_t zero_data = 0;
    
    // 解锁Flash
    fmc_unlock();
    
    // 清除标志位
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR |
                   FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
    
    // 擦除包含设备信息的页
    if(fmc_page_erase(DEVICE_INFO_ADDR) == FMC_READY)
    {
        // 等待操作完成
        while(FMC_BUSY == fmc_flag_get(FMC_FLAG_END));
        
        // 写入0到APP有效标志位置
        fmc_word_program(DEVICE_INFO_ADDR, zero_data);
        
        // 等待操作完成
        while(FMC_BUSY == fmc_flag_get(FMC_FLAG_END));
    }
    
    // 锁定Flash
    fmc_lock();
    
    // 2. 关闭所有中断
    __disable_irq();
    
    // 3. 关闭所有外设
    usart_deinit(USART0);
    gpio_deinit(GPIOA);
    gpio_deinit(GPIOE);  // LED所在的GPIO端口
    rcu_deinit();
    
    // 4. 设置跳转标志
    *(__IO uint32_t*)0x20000000 = 0x55AA55AA;
    
    // 5. 执行系统复位
    NVIC_SystemReset();
}

